#include "rwlock.h"

int pthread_rwlock_init(pthread_rwlock_t * lock /*, pthread_rwlockattr_t *attr */)
{
	active_readers = 0;
	pending_readers = 0;
	pending_writers = 0;
	pthread_mutex_init(&lock->mutex, NULL);
	pthread_cond_init(&lock->ok_to_read, NULL);
	pthread_cond_init(&lock->ok_to_write, NULL);
	return 0;
}

int pthread_rwlock_destroy(pthread_rwlock_t * lock) 
{
	pthread_mutex_destroy(&lock->mutex);
	pthread_cond_destroy(&lock->ok_to_read);
	pthread_cond_destroy(&lock->ok_to_write);
	return 0;
}

int pthread_rwlock_rdlock(pthread_rwlock_t * lock) 
{
#if 1	
	pthread_mutex_lock(&lock->mutex);
	lock->pending_readers++;
	while(lock->active_readers < 0) /* the write lock locked */
	pthread_cond_wait(&lock->ok_to_read, &lock->mutex);
	lock->pending_readers--;
	lock->active_readers++;
	pthread_mutex_unlock(&lock->mutex);
#endif
	return 0;
}

int pthread_rwlock_wrlock(pthread_rwlock_t * lock)
{
#if 1	
	pthread_mutex_lock(&lock->mutex);
	lock->pending_writers++;
	while(lock->active_readers) /* the write lock or read lock locked */
	pthread_cond_wait(&lock->ok_to_write, &lock->mutex);
	lock->pending_writers--;
	lock->active_readers = -1;
	pthread_mutex_unlock(&lock->mutex);
#endif

	return 0;
}

int pthread_rwlock_unlock(pthread_rwlock_t * lock)
{
#if 1	
	pthread_mutex_lock(&lock->mutex);
	assert(lock->active_readers)
	if (lock->active_readers > 0) /* release the read lock */
	{
		lock->active_readers--;
		if (lock->active_readers == 0) /* no read lock locked */
		{
			pthread_cond_signal(&lock->ok_to_write);
		}
	} 
	else if (lock->active_readers < 0) /* release the write lock */
	{
		lock->active_readers=0;
		/* it may be different, when write lock has higher priority than read lock */
		if (lock->pending_readers > 0) 
		{
			pthread_cond_broadcast(&lock->ok_to_read);
		} 
		else if (lock->pending_writers > 0) 
		{
			pthread_cond_signal(&lock->ok_to_write);
		}
	}
	pthread_mutex_unlock(&lock->mutex);
#endif
	return 0;
}
